﻿using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Sherwood.Configuration;
using Sherwood.Content.Contracts;
using Sherwood.Content.Tests;

namespace Sherwood.Content.UpdateServices.Tests
{

    public class MockedUpdateEnvironment
    {
        public MockFactory Mocks{ get; private set;}
        public Mock<IMeta> Meta { get; private set; }
        public Mock<IClient> Client { get; private set; }
        public Mock<IRecord> Record { get; private set; }
        public Mock<IMetaRepository> MetaRepository { get; set; }
        public Mock<IRecordRepository<IRecord>> Records { get; set; }
        public Mock<IClientRepository> Clients { get; private set; }
        public Mock<IMetaXmlUpdater> XmlUpdater { get; private set; }
        public Mock<ISearchDocumentModifier> SearchDocumentModifier { get; private set; }
        public Mock<ISearchDocumentService> SearchDocumentService { get; private set; }
        public Mock<ISearchDocument> SearchDocument { get; private set; }
        public Mock<IConfigRepository> Config { get; private set; }
        public Mock<IPluginProvider> Plugins { get; private set; }

        [TestInitialize]
        public void SetupMockedEnvironment()
        {
            Mocks = new MockFactory(MockBehavior.Default);
            Config = Mocks.Create<IConfigRepository>();
            Client = Mocks.Create<IClient>();
            Record = Mocks.Create<IRecord>();
            Meta = Mocks.Create<IMeta>();
            Records = Mocks.Create<IRecordRepository<IRecord>>();
            Clients = Mocks.Create<IClientRepository>();
            XmlUpdater = Mocks.Create<IMetaXmlUpdater>();
            SearchDocumentModifier = Mocks.Create<ISearchDocumentModifier>();
            SearchDocument = Mocks.Create<ISearchDocument>();
            SearchDocumentService = Mocks.Create<ISearchDocumentService>();
            Plugins = Mocks.Create<IPluginProvider>();
            MetaRepository = Mocks.Create<IMetaRepository>();

            SearchDocumentModifier
                .Setup(s => s.Fill(It.IsAny<ISearchDocument>(), It.IsAny<IRecord>()))
                .Callback<ISearchDocument, IRecord>((doc, r) => doc.Title += ", searchable")
                .Verifiable();

            Clients
                .SetupGet(repository => repository["SampleClient"])
                .Returns(() => Client.Object)
                .Verifiable();

            Client
                .SetupGet(c => c.PublicKey)
                .Returns(() => SampleClient.PublicKey);

            Records
                .Setup(r => r.GetByReferenceId("SampleClient", "1"))
                .Returns(() => Record.Object)
                .Verifiable();

            XmlUpdater
                .Setup(xu => xu.FromXml(Record.Object, Client.Object,
                                        It.Is<string>(v => string.IsNullOrEmpty(v)),
                                        UpdateMode.CreateOrUpdate,
                                        It.IsAny<XmlReader>()))
                .Returns(() => Meta.Object)
                .Verifiable();

            SearchDocumentService
                .Setup(s => s.CreateDocument(It.IsAny<IRecord>()))
                .Returns(() => SearchDocument.Object);

            SearchDocumentService
                .Setup(s => s.PublishDocuments(It.IsAny<IEnumerable<ISearchDocument>>()))
                .Callback<IEnumerable<ISearchDocument>>(documents => Assert.IsTrue(documents.Count() == 0 || documents.Any(d => d.Title != null && d.Title.EndsWith(", searchable"))))
                .Verifiable();

            Plugins
                .Setup(p => p.InstantiatePlugins<ISearchDocumentModifier>(It.IsAny<string>(), It.IsAny<bool>()))
                .Returns(() => new[] {SearchDocumentModifier.Object});

            Client.SetupGet(client1 => client1.Id).Returns("SampleClient");

            SearchDocument.SetupProperty(d => d.Title);

            var dataSessionProvider = Mocks.Create<IDataSessionProvider>();
            var dataSessionScope = Mocks.Create<IDataSessionScope>();
            dataSessionScope.Setup(s => s.Complete());
            dataSessionScope.Setup(s => s.Dispose());
            dataSessionProvider.Setup(p => p.CreateScope()).Returns(() => dataSessionScope.Object);

            DependencyInjection.Container.RegisterInstance(Plugins.Object);
            DependencyInjection.Container.RegisterInstance(Config.Object);
            DependencyInjection.Container.RegisterInstance(dataSessionProvider.Object);
            DependencyInjection.Container.RegisterInstance("ArticleMeta", XmlUpdater.Object);
            DependencyInjection.Container.RegisterInstance(Clients.Object);
            DependencyInjection.Container.RegisterInstance(Records.Object);
            DependencyInjection.Container.RegisterInstance(SearchDocument.Object);
            DependencyInjection.Container.RegisterInstance(SearchDocumentService.Object);
        }
    }
}